home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / xvisrc.zip / SUNBACK.C < prev    next >
C/C++ Source or Header  |  1992-07-28  |  11KB  |  534 lines

  1. #ifndef lint
  2. static char *sccsid = "@(#)sunback.c    2.1 (Chris & John Downey) 7/29/92";
  3. #endif
  4.  
  5. /***
  6.  
  7. * program name:
  8.     xvi
  9. * function:
  10.     PD version of UNIX "vi" editor, with extensions.
  11. * module name:
  12.     sunback.c
  13. * module function:
  14.     Terminal interface module for SunView: module for linking to
  15.     main program.
  16. * history:
  17.     STEVIE - ST Editor for VI Enthusiasts, Version 3.10
  18.     Originally by Tim Thompson (twitch!tjt)
  19.     Extensive modifications by Tony Andrews (onecom!wldrdg!tony)
  20.     Heavily modified by Chris & John Downey
  21. ***/
  22.  
  23. #include "xvi.h"
  24.  
  25. /*
  26.  * Exported.
  27.  */
  28. unsigned int    Rows = 0;             /* screen dimensions */
  29. unsigned int    Columns = 0;
  30.  
  31. /*
  32.  * These are used to optimize output.
  33.  */
  34. static    int    real_row, real_col;
  35. static    int    virt_row, virt_col;
  36. static    bool_t    optimize;
  37.  
  38. #define NO_COLOUR    -1
  39.  
  40. static int    old_colour = NO_COLOUR;
  41.  
  42. /*
  43.  * Update real cursor position.
  44.  *
  45.  * SunView can be painfully slow, at least on Sun 3's and 386i's, but
  46.  * it's difficult to know the best way of optimizing it. The number of
  47.  * characters sent to the display probably isn't really significant,
  48.  * because it isn't a terminal. The things that take the most time are
  49.  * more likely to be calculations (especially divisions &
  50.  * multiplications) & manipulating bit maps. The bitmap for a single
  51.  * character has to be xor'ed twice for each cursor movement, since
  52.  * terminal subwindows use a reverse video block cursor.
  53.  */
  54. #define MAXCMOVES    3    /*
  55.                  * This is a guess at the probable
  56.                  * maximum number of individual cursor
  57.                  * movements that's worthwhile to
  58.                  * avoid the calculations involved in
  59.                  * an absolute goto.
  60.                  */
  61. #ifndef ABS
  62. #    define ABS(n) ((n) < 0 ? -(n) : (n))
  63. #endif
  64.  
  65. static void
  66. xyupdate()
  67. {
  68.     int hdisp,    /* horizontal (rightward) displacement wanted */
  69.     vdisp,    /* vertical (downward) displacement wanted */
  70.     ahdisp,    /* absolute horizontal displacement wanted */
  71.     avdisp,    /* absolute vertical displacement wanted */
  72.     homedisp;    /* total displacement from home position */
  73.  
  74.     if (optimize) {
  75.     if (virt_col == real_col && virt_row == real_row)
  76.         /*
  77.          * Nothing to do.
  78.          */
  79.         return;
  80.     } else {
  81.         hdisp = virt_col - real_col;
  82.         vdisp = virt_row - real_row;
  83.         ahdisp = ABS(hdisp);
  84.         avdisp = ABS(vdisp);
  85.     }
  86.     }
  87.     homedisp = virt_row + virt_col;
  88.     /*
  89.      * Is it worth sending a cursor home sequence?
  90.      */
  91.     if (homedisp < MAXCMOVES && (!optimize || homedisp < avdisp + ahdisp)) {
  92.     fputs("\033[H", stdout);
  93.     real_row = real_col = 0;
  94.     ahdisp = hdisp = virt_col;
  95.     avdisp = vdisp = virt_row;
  96.     optimize = TRUE;
  97.     }
  98.     if (optimize) {
  99.     /*
  100.      * Is it worth sending a carriage return?
  101.      */
  102.     if (hdisp < 0 && virt_col < ahdisp && virt_col < MAXCMOVES) {
  103.         putc('\r', stdout);
  104.         real_col = 0;
  105.         ahdisp = hdisp = virt_col;
  106.     }
  107.     if (hdisp == 0 && vdisp == 0) {
  108.         /*
  109.          * We're already there, so there's nothing to do.
  110.          */
  111.         return;
  112.     }
  113.     /*
  114.      * Calculate total absolute displacement to see
  115.      * whether it's worthwhile doing any of this.
  116.      */
  117.     if (ahdisp + avdisp <= MAXCMOVES) {
  118.         for (; real_col < virt_col; real_col++)
  119.         /*
  120.          * Do non-destructive spaces.
  121.          */
  122.         fputs("\033[C", stdout);
  123.         for (; real_col > virt_col; real_col--)
  124.         /*
  125.          * Do backspaces.
  126.          */
  127.         putc('\b', stdout);
  128.         for (; real_row < virt_row; real_row++)
  129.         /*
  130.          * Go down.
  131.          */
  132.         putc('\n', stdout);
  133.         for (; real_row > virt_row; real_row--)
  134.         /*
  135.          * Go up.
  136.          */
  137.         fputs("\033[A", stdout);
  138.         return;
  139.     }
  140.     /*
  141.      * It isn't worthwhile. Give up & send an absolute
  142.      * goto.
  143.      */
  144.     }
  145.     fprintf(stdout, "\033[%d;%dH", virt_row + 1, virt_col + 1);
  146.     real_row = virt_row;
  147.     real_col = virt_col;
  148.     optimize = TRUE;
  149. }
  150.  
  151. /*
  152.  * Flush any pending output, including cursor position.
  153.  */
  154. void
  155. flush_output()
  156. {
  157.     xyupdate();
  158.     (void) fflush(stdout);
  159. }
  160.  
  161. /*
  162.  * Put out a "normal" character, updating the cursor position.
  163.  */
  164. void
  165. outchar(c)
  166. register int    c;
  167. {
  168.     xyupdate();
  169.     putc(c, stdout);
  170.     if (++virt_col >= Columns) {
  171.     virt_col = 0;
  172.     if (++virt_row >= Rows)
  173.         --virt_row;
  174.     real_row = virt_row;
  175.     }
  176.     real_col = virt_col;
  177. }
  178.  
  179. /*
  180.  * Put out a "normal" string, updating the cursor position.
  181.  */
  182. void
  183. outstr(s)
  184. register char    *s;
  185. {
  186.     xyupdate();
  187.     for (; *s; s++)
  188.     {
  189.     putc(*s, stdout);
  190.     if (++virt_col >= Columns)
  191.     {
  192.         virt_col = 0;
  193.         if (++virt_row >= Rows)
  194.         --virt_row;
  195.     }
  196.     }
  197.     real_row = virt_row;
  198.     real_col = virt_col;
  199. }
  200.  
  201. /*
  202.  * Beep at the user.
  203.  */
  204. void
  205. alert()
  206. {
  207.     putc('\007', stdout);
  208.     (void) fflush(stdout);
  209. }
  210.  
  211. /*
  212.  * Get a hexadecimal number from the front end process.
  213.  */
  214. static
  215. hexnumber()
  216. {
  217.     register int x;
  218.  
  219.     x = 0;
  220.     for (;;) {
  221.     register int c;
  222.  
  223.     c = inch(0);
  224.     if (c == ';')
  225.         return x;
  226.     if (!is_xdigit(c))
  227.         return -1;
  228.     x = (x << 4) | hex_to_bin(c);
  229.     }
  230. }
  231.  
  232. /*
  233.  * Get single character or control sequence from front-end process.
  234.  * The following control sequences are understood:
  235.  *
  236.  * Sequence            Meaning
  237.  *
  238.  * PREFIXCHAR 'k'        up arrow key pressed
  239.  * PREFIXCHAR 'j'        down arrow key pressed
  240.  * PREFIXCHAR '\b'        left arrow key pressed
  241.  * PREFIXCHAR ' '        right arrow key pressed
  242.  * PREFIXCHAR CTRL('F')        page down key pressed
  243.  * PREFIXCHAR CTRL('B')        page up key pressed
  244.  * PREFIXCHAR 'H'        home key pressed
  245.  * PREFIXCHAR 'L'        end key pressed
  246.  * PREFIXCHAR PREFIXCHAR    PREFIXCHAR pressed
  247.  * PREFIXCHAR 'p' hexnum ';' hexnum ';'
  248.  *                mouse button pressed at row & column
  249.  *                specified by the digits.
  250.  * PREFIXCHAR 'm' hexnum ';' hexnum ';' hexnum ';' hexnum ';'
  251.  *                mouse dragged with middle button held
  252.  *                down. Numbers give starting row &
  253.  *                column, then ending row & column, in
  254.  *                that order.
  255.  *
  256.  * PREFIXCHAR is currently control-R. A `hexnum' is 0 or more
  257.  * hexadecimal digits.
  258.  *
  259.  * Any other process run in the same tty subwindow (with the ":!" or
  260.  * "sh" commands) will also receive the same sequences for the events
  261.  * shown, but using control-R as a prefix should be reasonably safe.
  262.  *
  263.  * The sequence for mouse clicks is dealt with by mouseposn().
  264.  */
  265. int
  266. inchar(timeout)
  267. long    timeout;
  268. {
  269.     for (;;) {
  270.     register int    c;
  271.  
  272.     if ((c = inch(timeout)) == PREFIXCHAR) {
  273.     /*
  274.      * This looks like the beginning of a control sequence.
  275.      */
  276.         switch (c = inch(0)) {
  277.         case PREFIXCHAR:
  278.             return PREFIXCHAR;
  279.         case CTRL('B'): case CTRL('F'):
  280.         case 'H': case 'L':
  281.         case '\b': case ' ':
  282.         case 'j': case 'k':
  283.             /*
  284.              * This looks like a function
  285.              * key.
  286.              */
  287.             if (State == NORMAL) {
  288.             return c;
  289.             } else {
  290.             alert();
  291.             continue;
  292.             }
  293.         case 'm':
  294.         {
  295.             unsigned row1, row2, col1, col2;
  296.  
  297.             /*
  298.              * Even if we aren't in normal
  299.              * mode here, we have to call
  300.              * hexnumber() to eat all the
  301.              * hex. digits we should be
  302.              * getting.
  303.              */
  304.             if (
  305.             (row1 = hexnumber()) >= 0
  306.             &&
  307.             (row2 = hexnumber()) >= 0
  308.             &&
  309.             (col1 = hexnumber()) >= 0
  310.             &&
  311.             (col2 = hexnumber()) >= 0
  312.             &&
  313.             State == NORMAL
  314.             ) {
  315.             mousedrag(row1, row2, col1, col2);
  316.             }
  317.             continue;
  318.         }
  319.         case 'p':
  320.         {
  321.             unsigned row, col;
  322.  
  323.             /*
  324.              * Even if we aren't in normal
  325.              * mode here, we have to call
  326.              * hexnumber() to eat all the
  327.              * hex. digits we should be
  328.              * getting.
  329.              */
  330.             if (
  331.             (row = hexnumber()) >= 0
  332.             &&
  333.             (col = hexnumber()) >= 0
  334.             &&
  335.             State == NORMAL
  336.             ) {
  337.             mouseclick(row, col);
  338.             }
  339.             continue;
  340.         }
  341.         default:
  342.             continue;
  343.         }
  344.     } else if (c == CTRL('Z') && State == NORMAL) {
  345.         /*
  346.          * This isn't reasonable. Job control isn't
  347.          * available here because this process wasn't
  348.          * started from a shell (it was started by the
  349.          * SunView Notifier). They can always use
  350.          * another window to run commands.
  351.          */
  352.         alert();
  353.         continue;
  354.     } else {    /* It's just a normal character. */
  355.         return c;
  356.     }
  357.     }
  358. }
  359.  
  360. static time_t    starttime;
  361.  
  362. /*
  363.  * Initialise the terminal interface.
  364.  *
  365.  * This must be done before any screen-based i/o is performed.
  366.  */
  367. void
  368. tty_open(prows, pcolumns)
  369. unsigned int *prows,
  370.          *pcolumns;
  371. {
  372.     /*
  373.      * If sys_startv() hasn't already got valid values for the
  374.      * window size from its TIOCGWINSZ ioctl, something is
  375.      * seriously wrong with SunOS.
  376.      */
  377.     Rows = *prows;
  378.     Columns = *pcolumns;
  379.  
  380.     (void) time(&starttime);
  381.  
  382. #ifdef sparc
  383.     /*
  384.      * Unfortunately, this implementation still doesn't give us
  385.      * scrolling windows, but SparcStations are fast enough that
  386.      * it doesn't really matter.
  387.      */
  388.     set_param(P_jumpscroll, js_OFF, (char **) NULL);
  389. #endif
  390.  
  391.     {
  392.     /*
  393.      * These escape sequences may be generated by the
  394.      * arrow keys, depending on how the defaults database
  395.      * has been set up. All other function keys (page up,
  396.      * page down, etc.) should be received as function
  397.      * keys & handled appropriately by the front end
  398.      * process.
  399.      */
  400.     static char *mapargs[] = {
  401.         "\033[A",    "k",
  402.         "\033[B",    "j",
  403.         "\033[C",    "l",
  404.         "\033[D",    "h",
  405.         NULL
  406.     };
  407.     char **argp;
  408.  
  409.     for (argp = mapargs; *argp != NULL; argp += 2) {
  410.         xvi_keymap(argp[0], argp[1]);
  411.     }
  412.     }
  413. }
  414.  
  415. void
  416. tty_startv()
  417. {
  418.     old_colour = NO_COLOUR;
  419.     optimize = FALSE;
  420. }
  421.  
  422. /*
  423.  * Set terminal into the mode it was in when we started.
  424.  */
  425. void
  426. tty_endv()
  427. {
  428.     flush_output();
  429. }
  430.  
  431. /*
  432.  * Tell front end process to quit.
  433.  */
  434. void
  435. tty_close()
  436. {
  437.     time_t    stayuptime, now;
  438.  
  439.     /*
  440.      * If we're immediately crashing with an error message, give
  441.      * them a chance (5 seconds) to read it.
  442.      */
  443.     stayuptime = starttime + 5;
  444.     if ((now = time((time_t *) 0)) < stayuptime)
  445.     sleep(stayuptime - now);
  446.     write(3, "q", 1);
  447. }
  448.  
  449. void
  450. tty_goto(row, col)
  451. int    row, col;
  452. {
  453.     virt_row = row;
  454.     virt_col = col;
  455. }
  456.  
  457. /*
  458.  * Erase the entire current line.
  459.  */
  460. void
  461. erase_line()
  462. {
  463.     xyupdate();
  464.     fputs("\033[K", stdout);
  465. }
  466.  
  467. /*
  468.  * Insert one line.
  469.  */
  470. void
  471. insert_line()
  472. {
  473.     xyupdate();
  474.     fputs("\033[L", stdout);
  475. }
  476.  
  477. /*
  478.  * Delete one line.
  479.  */
  480. void
  481. delete_line()
  482. {
  483.     xyupdate();
  484.     fputs("\033[M", stdout);
  485. }
  486.  
  487. /*
  488.  * Erase display (may optionally home cursor).
  489.  */
  490. void
  491. erase_display()
  492. {
  493.     putc('\f', stdout);
  494.     optimize = FALSE;
  495.     old_colour = NO_COLOUR;
  496. }
  497.  
  498. /*
  499.  * Set the specified colour. Just does standout/standend mode for now.
  500.  *
  501.  * Colour mapping is as follows:
  502.  *
  503.  *    0    (default systemcolour)    normal
  504.  *    1    (default colour)    normal
  505.  *    2    (default statuscolour)    reverse video
  506.  */
  507. void
  508. set_colour(c)
  509. int    c;
  510. {
  511.     if (c == 1) {
  512.     c = 0;
  513.     } else if (c > 2) {
  514.     c = 2;
  515.     }
  516.     if (c != old_colour) {
  517.     xyupdate();
  518.     fputs((c ? "\033[7m" : "\033[m"), stdout);
  519.     old_colour = c;
  520.     }
  521. }
  522.  
  523. /*
  524.  * Insert the given character at the cursor position.
  525.  */
  526. void
  527. inschar(c)
  528. char    c;
  529. {
  530.     xyupdate();
  531.     fputs("\033[@", stdout);
  532.     outchar(c);
  533. }
  534.